﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Windows.Forms;
using Wpf = System.Windows.Controls;
using System.Windows.Media;
using System.Xml;
using PingFM;
using WindowsLive.Writer.BlogClient;
using WindowsLive.Writer.BlogClient.Clients;
using WindowsLive.Writer.CoreServices;
using WindowsLive.Writer.Extensibility.BlogClient;
using System.Threading;
using System.Threading.Tasks;

namespace Toth.WLW.Plugins
{
	public partial class FormXPollinate : Form
	{

		#region Members
		
		private List<Blog> _allBlogs;
		private BlogPost _sourceBlogPost;
		private BlogPost _publishedBlogPost;
		private Blog _sourceBlog;
		private string _sourceBlogId;
		private bool _isUpdatingCheckBoxList;
		private bool _isOptionsDialog;

        private enum CommentPolicy
        {
            Default,
            Open,
            Closed
        }

        private enum PingPolicy
        {
            Default,
            Open,
            Closed
        }

		#endregion
		
		#region Constructors

		/// <summary>
		/// Use this to display the options dialog.
		/// </summary>
		public FormXPollinate()
		{
			InitializeComponent();

			_isOptionsDialog = true;
			this.Text = Properties.Resources.FormTitleOptions;
			labelTop.Text = Properties.Resources.FormTopLabelOptions;
		}

		/// <summary>
		/// Use this to display the post dialog.
		/// </summary>
		/// <param name="sourceBlogId">The unique ID of the source post.</param>
		/// <param name="sourceBlogPost">The source BlogPost object.</param>
		public FormXPollinate(string sourceBlogId, BlogPost sourceBlogPost)
			: this()
		{
			_sourceBlogPost = sourceBlogPost;
			_sourceBlogId = sourceBlogId;
			_isOptionsDialog = false;
			this.Text = Properties.Resources.FormTitlePost;
			labelTop.Text = Properties.Resources.FormTopLabelPost;
		}

		#endregion

		#region Form Events

		private void formCrossPost_Load(object sender, EventArgs e)
		{
			// Make sure our assembly has been loaded
			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

			SetupBlogTab();
			SetupPingFMTab();
		}

		private void formCrossPost_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (backgroundWorkerPost.IsBusy)
			{
				e.Cancel = true;
			}
		}

		System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			Assembly ayResult = null;
			string sShortAssemblyName = args.Name.Split(',')[0];
			Assembly[] ayAssemblies =
			AppDomain.CurrentDomain.GetAssemblies();

			foreach (Assembly ayAssembly in ayAssemblies)
			{
				if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0])
				{
					ayResult = ayAssembly;
					break;
				}
			}
			return ayResult;
		}

		#endregion

		#region Methods

        private void AddService(Wpf.ComboBox comboBox, PingFMApi.ServiceMethods service)
        {
            Wpf.ComboBoxItem item = new Wpf.ComboBoxItem();
            Wpf.StackPanel panel = new Wpf.StackPanel();
            panel.Orientation = Wpf.Orientation.Horizontal;
            ImageSourceConverter converter = new ImageSourceConverter();
            Wpf.Image image = new Wpf.Image();
            image.Source = (ImageSource)converter.ConvertFromString(service.Icon);
            image.Width = 16;
            image.Height = 16;
            image.ImageFailed += new EventHandler<System.Windows.ExceptionRoutedEventArgs>(image_ImageFailed);
            panel.Children.Add(image);
            Wpf.TextBlock block = new Wpf.TextBlock();
            block.Text = string.Format("{0} ({1})", service.Name, service.Trigger);
            block.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            panel.Children.Add(block);
            item.Content = panel;
            item.Tag = service;
            comboBox.Items.Add(item);
            
        }

        void image_ImageFailed(object sender, System.Windows.ExceptionRoutedEventArgs e)
        {
            e.Handled = true; ;
        }

        private void AddTrigger(Wpf.ComboBox comboBox, PingFMApi.Trigger trigger)
        {
            Wpf.ComboBoxItem item = new Wpf.ComboBoxItem();
            item.Content = string.Format("#{0}", trigger.ID);
            item.Tag = trigger;
            comboBox.Items.Add(item);
        }

        private void AddDefaultItem(Wpf.ComboBox comboBox, string itemText)
        {
            comboBox.Items.Add(new Wpf.ComboBoxItem{ Content = itemText, Tag = itemText});
        }

		private void SetupPingFMTab()
		{
			// Get all the PingFM application settings
			string pingFMAPIKey = ApplicationEnvironment.UserSettingsRoot.GetString(XPollinate.PingFMAPIKey, string.Empty);
			bool postToPingFM = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PostToPingFMOption, false);
			bool postToPingFMBlogs = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PingFMPostToBlogs, false);
			bool postToPingFMMicroBlogs = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PingFMPostToMicroBlogs, false);
			bool postToPingFMStatuses = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PingFMPostToStatuses, false);
			string pingFMMicroBlogTemplate = ApplicationEnvironment.UserSettingsRoot.GetString(XPollinate.PingFMMicroBlogTemplate, Properties.Resources.DefaultPingFMTemplate);
			string pingFMStatusTemplate = ApplicationEnvironment.UserSettingsRoot.GetString(XPollinate.PingFMStatusTemplate, Properties.Resources.DefaultPingFMTemplate);
			bool postToBlogsShortenLinks = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PingFMPostToBlogShortenLinks, false);
			bool postToBlogsBookmarkLinks = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PingFMPostToBlogBookmarkLinks, false);

			// Figure out if the application is configured with an API key
			SetupPingFMAPIDefaults(pingFMAPIKey);

			// If we have an api key, set the default posting setting
			if (!string.IsNullOrEmpty(pingFMAPIKey))
			{
				checkBoxPostToPingFM.Checked = postToPingFM;
			}

			// Setup all other ping defaults
			checkBoxPingBlogs.Checked = postToPingFMBlogs;
			checkBoxPingMicroBlogs.Checked = postToPingFMMicroBlogs;
			checkBoxPingStatus.Checked = postToPingFMStatuses;
			checkBoxShortenLinks.Checked = postToBlogsShortenLinks;
			checkBoxBookmarkLinks.Checked = postToBlogsBookmarkLinks;
			textBoxPingMicroBlogTemplate.Text = pingFMMicroBlogTemplate;
			textBoxPingStatusTemplate.Text = pingFMStatusTemplate;
		}

        private void SetupPingFMAPIDefaults(string userAPIKey)
        {
            if (string.IsNullOrEmpty(userAPIKey))
            {
                textBoxPingFMApiKey.Text = string.Empty;
                checkBoxPostToPingFM.Checked = false;
                checkBoxPostToPingFM.Enabled = false;
                btnPingFMAPIKey.Text = Properties.Resources.ButtonPingFMAPIKeyEnter;
            }
            else
            {
                textBoxPingFMApiKey.Text = userAPIKey;
                checkBoxPostToPingFM.Enabled = true;
                btnPingFMAPIKey.Text = Properties.Resources.ButtonPingFMAPIKeyUpdate;

                SetupPingFMTriggers();
            }
        }


		private void SetupPingFMTriggers()
		{
			// Clear everything
			imageComboBoxPingFMBlogs.ComboBoxInstance.Items.Clear();
			imageComboBoxPingFMMicroBlogs.ComboBoxInstance.Items.Clear();
			imageComboBoxPingFMStatuses.ComboBoxInstance.Items.Clear();

			// Add in the default items
            AddDefaultItem(imageComboBoxPingFMBlogs.ComboBoxInstance, Properties.Resources.ComboBoxDefaultAll);
            AddDefaultItem(imageComboBoxPingFMMicroBlogs.ComboBoxInstance, Properties.Resources.ComboBoxDefaultAll);
            AddDefaultItem(imageComboBoxPingFMStatuses.ComboBoxInstance, Properties.Resources.ComboBoxDefaultAll);

			PingFMApi api = new PingFMApi(textBoxPingFMApiKey.Text);
			PingFMApi.PingResponse vr = api.Validate();
			if (!string.Equals(vr.Status, "OK"))
			{
				return;
			}

			// Get the user's triggers
			PingFMApi.TriggerResponse tr = api.GetTriggers();
			var statusTriggers = from t in tr.Triggers
								 where string.Equals(t.Method, "status", StringComparison.InvariantCultureIgnoreCase)
								 select t;
			var microBlogTriggers = from t in tr.Triggers
									where string.Equals(t.Method, "microblog", StringComparison.InvariantCultureIgnoreCase)
									select t;
			var blogTriggers = from t in tr.Triggers
							   where string.Equals(t.Method, "blog", StringComparison.InvariantCultureIgnoreCase)
							   select t;

			// Add in defaults and triggers
			if (statusTriggers.Count() > 0)
			{
                imageComboBoxPingFMStatuses.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingTrigger, "-1", null));
				foreach (var trigger in statusTriggers)
				{
					AddTrigger(imageComboBoxPingFMStatuses.ComboBoxInstance, trigger);
				}
			}
			if (microBlogTriggers.Count() > 0)
			{
                imageComboBoxPingFMMicroBlogs.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingTrigger, "-1", null));
				foreach (var trigger in microBlogTriggers)
				{
					AddTrigger(imageComboBoxPingFMMicroBlogs.ComboBoxInstance, trigger);
				}
			}
			if (blogTriggers.Count() > 0)
			{
                imageComboBoxPingFMBlogs.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingTrigger, "-1", null));
				foreach (var trigger in blogTriggers)
				{
					AddTrigger(imageComboBoxPingFMBlogs.ComboBoxInstance, trigger);
				}
			}

			// Get the user's services
			PingFMApi.ServicesResponse sr = api.GetServices();
			var statusServices = from s in sr.Services
								 where s.Methods.Contains("status")
								 select s;
			var microBlogServices = from s in sr.Services
									where s.Methods.Contains("microblog")
									select s;
			var blogServices = from s in sr.Services
							   where s.Methods.Replace("microblog", string.Empty).Contains("blog")
							   select s;

			// Add in defaults and services
			if (statusServices.Count() > 0)
			{
				imageComboBoxPingFMStatuses.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingStatuses, "-1", null));
				foreach (var service in statusServices)
				{
					AddService(imageComboBoxPingFMStatuses.ComboBoxInstance, service);
				}
			}
			if (microBlogServices.Count() > 0)
			{
                imageComboBoxPingFMMicroBlogs.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingStatuses, "-1", null));
				foreach (var service in microBlogServices)
				{
					AddService(imageComboBoxPingFMMicroBlogs.ComboBoxInstance, service);
				}
			}
			if (blogServices.Count() > 0)
			{
                imageComboBoxPingFMBlogs.ComboBoxInstance.Items.Add(new ComboBoxItem(Properties.Resources.ComboBoxDefaultPingStatuses, "-1", null));
				foreach (var service in blogServices)
				{
					AddService(imageComboBoxPingFMBlogs.ComboBoxInstance, service);
				}
			}

			// Pre-select the first item
            imageComboBoxPingFMBlogs.ComboBoxInstance.SelectedIndex = 0;
            imageComboBoxPingFMMicroBlogs.ComboBoxInstance.SelectedIndex = 0;
            imageComboBoxPingFMStatuses.ComboBoxInstance.SelectedIndex = 0;

		}

		private void SetupBlogTab()
		{
			// Get our default blog posting setting
			checkBoxPostToBlogs.Checked = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PostToBlogsOption, true);

			// Get all the defined blogs from the system
			BlogDescriptor[] allBlogDescriptors = BlogSettings.GetBlogs(true);
			_allBlogs = new List<Blog>();
			foreach (BlogDescriptor blog in allBlogDescriptors)
			{
				_allBlogs.Add(new Blog(blog.Id, blog.Name, blog.HomepageUrl));
			}

			// Get the Blog represented by the OriginalBlogPost
			_sourceBlog = _allBlogs.Find(delegate(Blog blogToFind) { return string.Equals(blogToFind.Id, _sourceBlogId); });

			// Get the default blogs that the user has set as targets
			List<Blog> defaultBlogs;
			byte[] defaultBlogsBinary = ApplicationEnvironment.UserSettingsRoot.GetByteArray(XPollinate.DefaultBlogsOption, new byte[] { });
			if (defaultBlogsBinary.Length == 0)
			{
				defaultBlogs = new List<Blog>();
			}
			else
			{
				MemoryStream ms = new MemoryStream(defaultBlogsBinary);
				BinaryFormatter bf = new BinaryFormatter();
				try
				{
					defaultBlogs = (List<Blog>)bf.Deserialize(ms);
				}
				catch (Exception)
				{
					// Something happened, maybe a program update changed the object graph
					// Reset the setting to an empty value
					ApplicationEnvironment.UserSettingsRoot.SetByteArray(XPollinate.DefaultBlogsOption, new byte[] { });
					defaultBlogs = new List<Blog>();
					MessageBox.Show("An error occured loading your previous blog settings. Your settings have been reset to the default.");
				}
			}

			Blog defaultBlog = null;

			if (!_isOptionsDialog)
			{
				defaultBlog = defaultBlogs.Find(delegate(Blog defaultBlogToFind) { return string.Equals(_sourceBlog.Id, defaultBlogToFind.Id); });
				if (defaultBlog == null || defaultBlog.TargetBlogIds == null || defaultBlog.TargetBlogIds.Count == 0)
				{
				}
				else
				{
					defaultBlog.TargetBlogIds.ForEach(delegate(string targetBlogId)
					{
						if (string.Equals(_sourceBlog.Id, targetBlogId))
						{
							// Target blog cannot be the same as source blog
							return;
						}

						if (_allBlogs.Exists(delegate(Blog blogToFind) { return string.Equals(blogToFind.Id, targetBlogId); }))
						{
							_sourceBlog.TargetBlogIds.Add(targetBlogId);
						}
					}
					);
				}

				// Add the source blog into the combobox
				comboBoxAllBlogs.Items.Add(_sourceBlog);
				comboBoxAllBlogs.SelectedIndex = 0;
				comboBoxAllBlogs.Enabled = false;

			}
			else
			{
				_allBlogs.ForEach(delegate(Blog blog)
				{
					defaultBlog = defaultBlogs.Find(delegate(Blog defaultBlogToFind) { return string.Equals(blog.Id, defaultBlogToFind.Id); });
					if (defaultBlog == null || defaultBlog.TargetBlogIds == null || defaultBlog.TargetBlogIds.Count == 0)
					{
						return;
					}
					defaultBlog.TargetBlogIds.ForEach(delegate(string targetBlogId)
					{
						if (string.Equals(blog.Id, targetBlogId))
						{
							// Target blog cannot be the same as source blog
							return;
						}

						if (_allBlogs.Exists(delegate(Blog blogToFind) { return string.Equals(blogToFind.Id, targetBlogId); }))
						{
							blog.TargetBlogIds.Add(targetBlogId);
						}
					}
					);
				}
				);

				// Add all the blogs into the combobox
				comboBoxAllBlogs.Items.AddRange(_allBlogs.ToArray());
				comboBoxAllBlogs.SelectedIndex = 0;
				comboBoxAllBlogs.Enabled = true;
			}


			// Get the summary default
			checkBoxSummary.Checked = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.PostSummaryOption, false);

			// Get the summary character length default
			textBoxSummaryCharacters.Text = ApplicationEnvironment.UserSettingsRoot.GetInt32(XPollinate.SummaryCharactersOption, 200).ToString();

			// Get the include header default
			checkBoxIncludeHeader.Checked = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.IncludeHeaderOption, false);

			// Get the include header text default
			textBoxHeaderText.Text = ApplicationEnvironment.UserSettingsRoot.GetString(XPollinate.HeaderTextOption, Properties.Resources.DefaultHeaderText).ToString();

			// Get the include footer default
			checkBoxIncludeFooter.Checked = ApplicationEnvironment.UserSettingsRoot.GetBoolean(XPollinate.IncludeFooterOption, false);

			// Get the include footer text default
			textBoxFooterText.Text = ApplicationEnvironment.UserSettingsRoot.GetString(XPollinate.FooterTextOption, Properties.Resources.DefaultHeaderText).ToString();

			// Get the Comment Policy Default
			BlogCommentPolicy commentPolicy = (BlogCommentPolicy)ApplicationEnvironment.UserSettingsRoot.GetInt32(XPollinate.CommentPolicyOption, Convert.ToInt32(BlogCommentPolicy.None));
			switch (commentPolicy)
			{
				case BlogCommentPolicy.Closed:
					radioButtonCommentPolicyClosed.Checked = true;
					break;
				case BlogCommentPolicy.Open:
					radioButtonCommentPolicyOpen.Checked = true;
					break;
				default:
					radioButtonCommentPolicyDefault.Checked = true;
					break;
			}

			// Get the PIng Policy default
			BlogTrackbackPolicy pingPolicy = (BlogTrackbackPolicy)ApplicationEnvironment.UserSettingsRoot.GetInt32(XPollinate.PingPolicyOption, Convert.ToInt32(BlogTrackbackPolicy.Unspecified));
			switch (pingPolicy)
			{
				case BlogTrackbackPolicy.Allow:
					radioButtonPingPolicyAllow.Checked = true;
					break;
				case BlogTrackbackPolicy.Deny:
					radioButtonPingPolicyDeny.Checked = true;
					break;
				default:
					radioButtonPingPolicyDefault.Checked = true;
					break;
			}

		}

		private void SaveBlogTab()
		{
			// Save the post to blogs option
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PostToBlogsOption, checkBoxPostToBlogs.Checked);

			// Save the target blogs
			MemoryStream ms = new MemoryStream();
			BinaryFormatter bf = new BinaryFormatter();
			bf.Serialize(ms, _allBlogs);
			ms.Position = 0;
			ms.Seek(0, SeekOrigin.Begin);
			ApplicationEnvironment.UserSettingsRoot.SetByteArray(XPollinate.DefaultBlogsOption, ms.ToArray());

			// Save the summary option
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PostSummaryOption, checkBoxSummary.Checked);

			// Save the summary characters option
			ApplicationEnvironment.UserSettingsRoot.SetInt32(XPollinate.SummaryCharactersOption, Int32.Parse(textBoxSummaryCharacters.Text));

			// Save the header option
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.IncludeHeaderOption, checkBoxIncludeHeader.Checked);

			// Save the header text option
			ApplicationEnvironment.UserSettingsRoot.SetString(XPollinate.HeaderTextOption, textBoxHeaderText.Text);

			// Save the footer option
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.IncludeFooterOption, checkBoxIncludeFooter.Checked);

			// Save the footer text option
			ApplicationEnvironment.UserSettingsRoot.SetString(XPollinate.FooterTextOption, textBoxFooterText.Text);

			// Save the CommentPolicy option
			BlogCommentPolicy commentPolicy = BlogCommentPolicy.None;
			if (radioButtonCommentPolicyDefault.Checked)
			{
				// Use default
			}
			else if (radioButtonCommentPolicyOpen.Checked)
			{
				commentPolicy = BlogCommentPolicy.Open;
			}
			else if (radioButtonCommentPolicyClosed.Checked)
			{
				commentPolicy = BlogCommentPolicy.Closed;
			}
			ApplicationEnvironment.UserSettingsRoot.SetInt32(XPollinate.CommentPolicyOption, Convert.ToInt32(commentPolicy));

			// Save the PingPolicy option
			BlogTrackbackPolicy pingPolicy = BlogTrackbackPolicy.Unspecified;
			if (radioButtonPingPolicyDefault.Checked)
			{
				// Use default
			}
			else if (radioButtonPingPolicyAllow.Checked)
			{
				pingPolicy = BlogTrackbackPolicy.Allow;
			}
			else if (radioButtonCommentPolicyClosed.Checked)
			{
				pingPolicy = BlogTrackbackPolicy.Deny;
			}
			ApplicationEnvironment.UserSettingsRoot.SetInt32(XPollinate.PingPolicyOption, Convert.ToInt32(pingPolicy));


		}

		private void SavePingFMTab()
		{
			// API Key
			ApplicationEnvironment.UserSettingsRoot.SetString(XPollinate.PingFMAPIKey, textBoxPingFMApiKey.Text);

			// Post to PingFM
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PostToPingFMOption, checkBoxPostToPingFM.Checked);

			// Post to PingFM Blogs
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PingFMPostToBlogs, checkBoxPingBlogs.Checked);

			// Post to PingFM MicroBlogs
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PingFMPostToMicroBlogs, checkBoxPingMicroBlogs.Checked);

			// Post to PingFM Status
			ApplicationEnvironment.UserSettingsRoot.SetBoolean(XPollinate.PingFMPostToStatuses, checkBoxPingStatus.Checked);

			// Microblog Template
			ApplicationEnvironment.UserSettingsRoot.SetString(XPollinate.PingFMMicroBlogTemplate, textBoxPingMicroBlogTemplate.Text);

			// Status Template
			ApplicationEnvironment.UserSettingsRoot.SetString(XPollinate.PingFMStatusTemplate, textBoxPingStatusTemplate.Text);

		}

		private void PostToPingFMBlog(
            string pingFMAPIKey,
            bool shortenLinks, 
            bool bookmarkLinks, 
            bool summarize, 
            int summaryCharacters,
            bool includeHeader,
            string headerText,
            bool includeFooter,
            string footerText,
            object triggerOrService)
		{

			// Setup the API
			PingFMApi api = new PingFMApi(pingFMAPIKey);

			// Do we bookmark or not?
			string servicesToExclude = null;
			if (!bookmarkLinks)
			{
				servicesToExclude = "delicious";
			}

			string contents = _publishedBlogPost.Contents;
			// Summarize if necessary
			if (summarize)
			{
				contents = Summarize(_publishedBlogPost, summaryCharacters);
			}
			// Replace any relative links with absolute ones
			contents = FixRelativeUrls(_sourceBlog.HomePageUrl, contents);

			// Add header and footer
			if (includeHeader)
			{
				contents = headerText + contents;
			}

			if (includeFooter)
			{
				contents = contents + footerText;
			}

			// Replace any placeholders in the text
			contents = ReplaceBlogPlaceholders(contents, _publishedBlogPost, _sourceBlog);

			// Do we shorten links or not?
			if (!shortenLinks)
			{
				contents = PreventShortenedLinks(contents);
			}

            PingFMApi.PingResponse blogResponse = DoPing(
                api,
                "blog",
                _sourceBlogPost.Title,
                contents,
                servicesToExclude,
                triggerOrService);

			if (blogResponse == null)
			{
				throw api.WebException;
			}
			else if (!string.Equals(blogResponse.Status, "OK", StringComparison.InvariantCultureIgnoreCase))
			{
				throw new Exception(blogResponse.Message);
			}

		}

        private void PostToPingFMMicroBlog(string pingFMAPIKey, string microBlogTemplate, object triggerOrService)
        {
            PingFMApi api = new PingFMApi(pingFMAPIKey);

            PingFMApi.PingResponse microBlogResponse = DoPing(
                api,
                "microblog",
                _sourceBlogPost.Title,
                ReplaceBlogPlaceholders(microBlogTemplate, _publishedBlogPost, _sourceBlog),
                null,
                triggerOrService);

			if (microBlogResponse == null)
			{
				throw api.WebException;
			}
			else if (!string.Equals(microBlogResponse.Status, "OK", StringComparison.InvariantCultureIgnoreCase))
			{
				throw new Exception(microBlogResponse.Message);
			}


        }

        private void PostToPingFMStatuses(string pingFMAPIKey, string statusTemplate, object triggerOrService)
        {
            PingFMApi api = new PingFMApi(pingFMAPIKey);
            PingFMApi.PingResponse statusResponse = DoPing(
                api,
                "status",
                _sourceBlogPost.Title,
                ReplaceBlogPlaceholders(statusTemplate, _publishedBlogPost, _sourceBlog),
                null,
                triggerOrService);

			if (statusResponse == null)
			{
				throw api.WebException;
			}
			else if (!string.Equals(statusResponse.Status, "OK", StringComparison.InvariantCultureIgnoreCase))
			{
				throw new Exception(statusResponse.Message);
			}
        }

		private PingFMApi.PingResponse DoPing(PingFMApi api, string method, string title, string body, string servicesToExclude, object triggerOrService)
		{
			string trigger = null;
			string service = null;

			if (triggerOrService is PingFMApi.Trigger)
			{
				trigger = ((PingFMApi.Trigger)triggerOrService).ID;
			}
			else
			{
				service = ((PingFMApi.ServiceMethods)triggerOrService).ID;
			}

			PingFMApi.PingResponse response = null;

            if (!string.IsNullOrEmpty(trigger))
            {
                response = api.Post(new PingFMApi.OutgoingMessage
                {
                    Body = body,
                    Title = title,
                    Trigger = trigger,
                    Exclude = servicesToExclude

                });
            }
            else
            {
                response = api.Post(new PingFMApi.OutgoingMessage
                {
                    Body = body,
                    Title = title,
                    Method = method,
                    Service = service,
                    Exclude = servicesToExclude
                });
            }

			return response;

		}

		private string PreventShortenedLinks(string contents)
		{
			contents = contents.Replace("href=\"http://", "href=\"*http://");
			contents = contents.Replace("href=\"https://", "href=\"*https://");
			return contents;
		}

		private string PostToBlog(
            Blog blogToPostTo, 
            bool summarize, 
            int summaryCharacters,
            bool includeHeader, 
            string headerText,
            bool includeFooter, 
            string footerText, 
            BlogCommentPolicy commentPolicy,
            BlogTrackbackPolicy pingBackPolicy)
		{

			// Get the target blog client
			BlogSettings targetBlogSettings = BlogSettings.ForBlogId(blogToPostTo.Id);
			IBlogClient targetBlogClient = BlogClientManager.CreateClient(targetBlogSettings);

			// Make a new post
			BlogPost crossPost = new BlogPost();

			// Copy the old data into the new post
			crossPost.CopyFrom(_publishedBlogPost);
			crossPost.ResetPostForNewBlog(targetBlogClient.Options);

			crossPost.Permalink = string.Empty;

			// Replace any relative links with absolute ones
			crossPost.Contents = FixRelativeUrls(_sourceBlog.HomePageUrl, crossPost.Contents);

			if (summarize)
			{
				crossPost.Contents = Summarize(crossPost, summaryCharacters);
			}

			if (includeHeader)
			{
				crossPost.Contents = headerText + crossPost.Contents;
			}

			if (includeFooter)
			{
				crossPost.Contents = crossPost.Contents + footerText;
			}

			// Comment Policy
			crossPost.CommentPolicy = commentPolicy;

			// Trackback/Ping Policy
			crossPost.TrackbackPolicy = pingBackPolicy;

			// Replace any placeholders in the text
			crossPost.Contents = ReplaceBlogPlaceholders(crossPost.Contents, _publishedBlogPost, _sourceBlog);

			// Post it
			string etag = string.Empty;
			XmlDocument postedDoc = null;
			string crossPostedId = targetBlogClient.NewPost(targetBlogSettings.HostBlogId, crossPost, NullNewCategoryContext.Instance, true, out etag, out postedDoc);

			// Get the new post fresh
			BlogPost createdPost = targetBlogClient.GetPost(targetBlogSettings.HostBlogId, crossPostedId);

			string postUri = createdPost.Permalink;
			if (!Uri.IsWellFormedUriString(postUri, UriKind.Absolute))
			{
				// make absolute from blog homepage.
				postUri = new Uri(
					new Uri(targetBlogSettings.HomepageUrl),
					new Uri(createdPost.Permalink, UriKind.Relative)).ToString();
			}

            if (postUri.StartsWith("https://"))
            {
                postUri = postUri.Replace("https://", "http://");
            }
            return postUri;

		}

		private void SetupBlogCheckboxes()
		{
			checkedListBoxBlogs.BeginUpdate();
			_isUpdatingCheckBoxList = true;

			// Clear the checked list box
			checkedListBoxBlogs.Items.Clear();

			Blog selectedBlog = null;

			if (_isOptionsDialog)
			{
				selectedBlog = _allBlogs[comboBoxAllBlogs.SelectedIndex];
			}
			else
			{
				selectedBlog = _sourceBlog;
			}

			// Add all other blogs to the checked list box
			_allBlogs.ForEach(delegate(Blog blog)
			{
				if (blog == selectedBlog)
				{
					return;
				}
				checkedListBoxBlogs.Items.Add(blog, selectedBlog.TargetBlogIds.Exists(delegate(string targetBlogId) { return string.Equals(targetBlogId, blog.Id); }) ? CheckState.Checked : CheckState.Unchecked);
			}
			);

			_isUpdatingCheckBoxList = false;
			checkedListBoxBlogs.EndUpdate();

		}


		private string FixRelativeUrls(string targetBlogHomePageUrl, string contents)
		{
			string baseUri = new Uri(targetBlogHomePageUrl).GetLeftPart(UriPartial.Authority);

			string result = contents.Replace("href=\"/", "href=\"" + baseUri + "/");
			result = result.Replace("src=\"/", "src=\"" + baseUri + "/");

			return result;
		}

		private string ReplaceBlogPlaceholders(string content, BlogPost sourceBlogPost, Blog sourceBlog)
		{
			content = content.Replace(Properties.Resources.PlaceHolderSourceBlogName, sourceBlog.Name);
			content = content.Replace(Properties.Resources.PlaceHolderSourceBlogUrl, sourceBlog.HomePageUrl);
			content = content.Replace(Properties.Resources.PlaceHolderSourceBlogPostTitle, sourceBlogPost.Title);
			content = content.Replace(Properties.Resources.PlaceHolderSourceBlogPostUrl, sourceBlogPost.Permalink);
			return content;
		}

		private string Summarize(BlogPost sourcePost, int summaryChars)
		{

			if (!string.IsNullOrEmpty(sourcePost.Excerpt))
			{
				return sourcePost.Excerpt;
			}

			string moreDots = "<span>...</span>";

			StringBuilder output = new StringBuilder();
			XmlWriterSettings set = new XmlWriterSettings();
			set.OmitXmlDeclaration = true;
			using (XmlWriter writer = XmlWriter.Create(output, set))
			{
				Sgml.SgmlReader reader = new Sgml.SgmlReader();
				reader.InputStream = new StringReader("<p>" + sourcePost.Contents + "</p>");
				SummaryReader sr = new SummaryReader(reader, summaryChars, moreDots);
				writer.WriteNode(sr, false);
			}

			string html = output.ToString();

			return html;
		}

		#endregion

		#region Control Events

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // This is a hack. If the panel is disabled early on, then the dropdown 
            // will not work anytime afterwards. Delaying disabling the panel until 
            // later makes the dropdown always work.
            if (tabControl1.SelectedTab.Name == tabPagePingFM.Name)
            {
                if (!checkBoxPostToPingFM.Checked && panelPostToPingFM.Enabled)
                {
                    panelPostToPingFM.Enabled = false;
                }
            }
        }

		private void checkBoxSummary_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBoxSummary.Checked)
			{
				panelSummary.Enabled = true;
				textBoxSummaryCharacters.Focus();
			}
			else
			{
				panelSummary.Enabled = false;
			}
		}

		private void textBoxSummaryCharacters_Validating(object sender, CancelEventArgs e)
		{
			int value;
			e.Cancel = !Int32.TryParse(textBoxSummaryCharacters.Text, out value);
		}

		private void checkBoxPostToBlogs_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBoxPostToBlogs.Checked)
			{
				panelPostToBlogs.Enabled = true;
			}
			else
			{
				panelPostToBlogs.Enabled = false;
			}
		}

		private void comboBoxAllBlogs_SelectedIndexChanged(object sender, EventArgs e)
		{
			SetupBlogCheckboxes();
		}

		private void checkedListBoxBlogs_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			if (!_isUpdatingCheckBoxList && _isOptionsDialog)
			{
				Blog checkedBlog = checkedListBoxBlogs.Items[e.Index] as Blog;
				Blog targetBlog = null;
				List<string> targetBlogIds = new List<string>();

				// Add the current item if it is checked (it is not yet in the checkeditems collection)
				if (e.NewValue == CheckState.Checked)
				{
					targetBlogIds.Add(checkedBlog.Id);
				}
				// Add the other previously checked items
				foreach (object blogObject in checkedListBoxBlogs.CheckedItems)
				{
					targetBlog = blogObject as Blog;
					// If the blog is currently checked, and is going to be unchecked, don't add it
					if (string.Equals(targetBlog.Id, checkedBlog.Id) && e.NewValue == CheckState.Unchecked)
					{
						// Don't add the item
					}
					else
					{
						targetBlogIds.Add(targetBlog.Id);
					}
				}
				// Update the object in our global collection (the one in the combobox is not the same object reference)
				Blog sourceBlog = _allBlogs[comboBoxAllBlogs.SelectedIndex];
				sourceBlog.TargetBlogIds = targetBlogIds;
			}
		}

		private void checkBoxIncludeHeader_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBoxIncludeHeader.Checked)
			{
				textBoxHeaderText.Enabled = true;
				textBoxHeaderText.Focus();
			}
			else
			{
				textBoxHeaderText.Enabled = false;
			}
		}

		private void checkBoxIncludeFooter_CheckedChanged(object sender, EventArgs e)
		{

		}

		private void btnPingFMAPIKey_Click(object sender, EventArgs e)
		{
			using (formPingFMAPIKey form = new formPingFMAPIKey(textBoxPingFMApiKey.Text))
			{
				DialogResult result = form.ShowDialog(this);

				if (result == DialogResult.OK)
				{
					SetupPingFMAPIDefaults(form.textBoxPingFMAPIKey.Text);
				}

			}

		}

		private void checkBoxPostToPingFM_CheckedChanged(object sender, EventArgs e)
		{
			panelPostToPingFM.Enabled = checkBoxPostToPingFM.Checked;
            imageComboBoxPingFMBlogs.IsEnabled = checkBoxPostToPingFM.Checked;
            imageComboBoxPingFMMicroBlogs.IsEnabled = checkBoxPostToPingFM.Checked;
            imageComboBoxPingFMStatuses.IsEnabled = checkBoxPostToPingFM.Checked;
        }

		private void pictureBoxPingFM_MouseDown(object sender, MouseEventArgs e)
		{
			// Open the browser to ping.fm.
			if (e.Clicks == 1)
			{
				Process.Start("http://ping.fm");
			}
		}

		private void backgroundWorkerPost_DoWork(object sender, DoWorkEventArgs e)
		{

		}

		private void backgroundWorkerPost_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			string message = e.UserState as string;


		}

		private void backgroundWorkerPost_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			buttonFinish.Enabled = true;


		}

		private void btnAccept_Click(object sender, EventArgs e)
		{
			if (_isOptionsDialog)
			{
				SaveBlogTab();
				SavePingFMTab();
				DialogResult = DialogResult.OK;
			}
			else
			{
                // Make sure we have something to do
                // TODO: Add HelloTxt
                if ((!checkBoxPostToBlogs.Checked || checkedListBoxBlogs.CheckedItems.Count == 0) &&
                    (!checkBoxPostToPingFM.Checked || (!checkBoxPingBlogs.Checked && !checkBoxPingMicroBlogs.Checked && !checkBoxPingStatus.Checked)))
	            {
                    MessageBox.Show(this, "Please select something to post to.", "xPollinate", MessageBoxButtons.OK, MessageBoxIcon.Error);
		            return;
	            }

                try
                {
                    // Get the published blog post so that all images are references with absolute paths
                    _publishedBlogPost = BlogClientManager.CreateClient(
                        BlogSettings.ForBlogId(_sourceBlogId)).
                        GetPost(_sourceBlogId, _sourceBlogPost.Id);

                    if (_publishedBlogPost == null)
                    {
                        MessageBox.Show(this, "This blog post must be published first.", "xPollinate", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }

                }
                catch (Exception)
                {
                    MessageBox.Show(this, "There was an error trying to get the contents of the original post from your source blog. Please check your internet connection and try again.", "xPollinate", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                // Toggle UI controls
				panelStatus.Visible = true;
				panelStatus.BringToFront();
				buttonFinish.Enabled = false;
				tabControl1.Visible = false;
				tabControl1.SendToBack();

                // Get variables from controls on our UI thread first
                bool includeHeader = checkBoxIncludeHeader.Checked;
                bool includeFooter = checkBoxIncludeFooter.Checked;
                bool summarize = checkBoxSummary.Checked;
                int summaryCharacters = -1;
                if (!int.TryParse(textBoxSummaryCharacters.Text, out summaryCharacters))
                {
                    summaryCharacters = 255;
                }
                string headerText = textBoxHeaderText.Text;
                string footerText = textBoxFooterText.Text;

                BlogCommentPolicy commentPolicy = BlogCommentPolicy.None;
                if (radioButtonCommentPolicyDefault.Checked)
                {
                    commentPolicy = BlogCommentPolicy.Unspecified;
                }
                else if (radioButtonCommentPolicyClosed.Checked)
                {
                    commentPolicy = BlogCommentPolicy.Closed;
                }
                else
                {
                    commentPolicy = BlogCommentPolicy.Open;
                }
                BlogTrackbackPolicy trackbackPolicy = BlogTrackbackPolicy.Unspecified;
                if (radioButtonPingPolicyDefault.Checked)
                {
                    trackbackPolicy = BlogTrackbackPolicy.Unspecified;
                }
                else if (radioButtonPingPolicyDeny.Checked)
                {
                    trackbackPolicy = BlogTrackbackPolicy.Deny;
                }
                else
                {
                    trackbackPolicy = BlogTrackbackPolicy.Allow;
                }
                List<Blog> blogsToPostTo = new List<Blog>();
                foreach (var blogObject in checkedListBoxBlogs.CheckedItems)
                {
                    blogsToPostTo.Add(blogObject as Blog);
                }

                // Start creating our background tasks
                List<Task> allTasks = new List<Task>();

                TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

                // Create task for Blogs
                if (checkBoxPostToBlogs.Checked && checkedListBoxBlogs.CheckedItems.Count > 0)
                {
                    wpfStatusControl.BlogGroupBox.Visibility = System.Windows.Visibility.Visible;
                    wpfStatusControl.BlogProgressBar.IsIndeterminate = true;

                    List<Task> blogTasks = new List<Task>();
                    foreach (Blog blogToPostTo in blogsToPostTo)
                    {
                        BlogItemControl blogItemControl = wpfStatusControl.AddBlogItem(blogToPostTo.Name);
                        Task<string> blogItemTask = new Task<string>((obj) =>
                        {
                            var blog = blogToPostTo;
                            return PostToBlog(blog, summarize, summaryCharacters, includeHeader, headerText, includeFooter, footerText, commentPolicy, trackbackPolicy);
                        }, blogItemControl);
                        Task bll = blogItemTask.ContinueWith(
                        (t) =>
                        {
                            BlogItemControl bic = t.AsyncState as BlogItemControl;

                            if (t.Exception != null)
                            {
                                bic.ShowError(t.Exception.Flatten().ToString());
                            }
                            else
                            {
                                bic.ShowSuccess(t.Result);
                            }
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                        blogTasks.Add(blogItemTask);
                        allTasks.Add(blogItemTask);

                        blogItemTask.Start();


                    }

                    var blogContinuation = Task.Factory.ContinueWhenAll(blogTasks.ToArray(), (t) =>
                        {
                            wpfStatusControl.BlogProgressBar.Value = 100;
                            wpfStatusControl.BlogProgressBar.IsIndeterminate = false;
                            
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);


                }



                // Create task for Ping.FM
                if (checkBoxPostToPingFM.Checked && (checkBoxPingBlogs.Checked || checkBoxPingMicroBlogs.Checked || checkBoxPingStatus.Checked))
                {
                    // Get UI control values
                    bool shortenLinks = checkBoxShortenLinks.Checked;
                    bool bookmarkLinks = checkBoxBookmarkLinks.Checked;
                    bool postToPingFMBlogs = checkBoxPingBlogs.Checked;
                    bool postToPingFMMicroBlogs = checkBoxPingMicroBlogs.Checked;
                    bool postToPingFMStatuses = checkBoxPingStatus.Checked;
                    string microBlogTemplate = textBoxPingMicroBlogTemplate.Text;
                    string statusTemplate = textBoxPingStatusTemplate.Text;
                    string pingFMApiKey = textBoxPingFMApiKey.Text;
                    object pingFMBlogObject = ((Wpf.ComboBoxItem)imageComboBoxPingFMBlogs.ComboBoxInstance.SelectedItem).Tag;
                    object pingFMStatusObject = ((Wpf.ComboBoxItem)imageComboBoxPingFMStatuses.ComboBoxInstance.SelectedItem).Tag;
                    object pingFMMicroBlogObject = ((Wpf.ComboBoxItem)imageComboBoxPingFMMicroBlogs.ComboBoxInstance.SelectedItem).Tag;

                    List<Task> pingTasks = new List<Task>();

                    wpfStatusControl.PingGroupBox.Visibility = System.Windows.Visibility.Visible;
                    wpfStatusControl.PingProgressBar.IsIndeterminate = true;

                    if (postToPingFMBlogs)
                    {

                        BlogItemControl blogItemControl = wpfStatusControl.AddPingItem("Ping.FM Blogs");
                        Task pingFMBlogTask = new Task((obj) =>
                        {
                            PostToPingFMBlog(pingFMApiKey, shortenLinks, bookmarkLinks, summarize, summaryCharacters, includeHeader, headerText, includeFooter, footerText, pingFMBlogObject);
                        }, blogItemControl);
                        Task bll = pingFMBlogTask.ContinueWith(
                        (t) =>
                        {
                            BlogItemControl bic = t.AsyncState as BlogItemControl;

                            if (t.Exception != null)
                            {
                                bic.ShowError(t.Exception.InnerException.ToString());
                            }
                            else
                            {
                                bic.ShowSuccess("http://ping.fm/recent");
                            }
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                        pingTasks.Add(pingFMBlogTask);
                        allTasks.Add(pingFMBlogTask);
                        pingFMBlogTask.Start();

                    }

                    if (postToPingFMMicroBlogs)
                    {

                        BlogItemControl blogItemControl = wpfStatusControl.AddPingItem("Ping.FM MicroBlogs");
                        Task pingFMMicroBlogTask = new Task((obj) =>
                        {
                            PostToPingFMMicroBlog(pingFMApiKey, microBlogTemplate, pingFMMicroBlogObject);
                        }, blogItemControl);
                        Task bll = pingFMMicroBlogTask.ContinueWith(
                        (t) =>
                        {
                            BlogItemControl bic = t.AsyncState as BlogItemControl;

                            if (t.Exception != null)
                            {
                                bic.ShowError(t.Exception.InnerException.ToString());
                            }
                            else
                            {
                                bic.ShowSuccess("http://ping.fm/recent");
                            }
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                        pingTasks.Add(pingFMMicroBlogTask);
                        allTasks.Add(pingFMMicroBlogTask);
                        pingFMMicroBlogTask.Start();

                    }

                    if (postToPingFMStatuses)
                    {

                        BlogItemControl blogItemControl = wpfStatusControl.AddPingItem("Ping.FM Statuses");
                        Task pingFMStatusTask = new Task((obj) =>
                        {
                            PostToPingFMStatuses(pingFMApiKey, microBlogTemplate, pingFMStatusObject);
                        }, blogItemControl);
                        Task bll = pingFMStatusTask.ContinueWith(
                        (t) =>
                        {
                            BlogItemControl bic = t.AsyncState as BlogItemControl;

                            if (t.Exception != null)
                            {
                                bic.ShowError(t.Exception.InnerException.ToString());
                            }
                            else
                            {
                                bic.ShowSuccess("http://ping.fm/recent");
                            }
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                        pingTasks.Add(pingFMStatusTask);
                        allTasks.Add(pingFMStatusTask);
                        pingFMStatusTask.Start();
                    }


                    var pingContinuation = Task.Factory.ContinueWhenAll(pingTasks.ToArray(), (t) =>
                        {
                            wpfStatusControl.PingProgressBar.Value = 100;
                            wpfStatusControl.PingProgressBar.IsIndeterminate = false;
                        }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                }

                var finalContinuation = Task.Factory.ContinueWhenAll(allTasks.ToArray(),
                    (t) =>
                    {
                        buttonFinish.Enabled = true;

                    }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

                

			}
		}


		#endregion

		class NullNewCategoryContext : INewCategoryContext
		{
			public static NullNewCategoryContext Instance = new NullNewCategoryContext();

			public void NewCategoryAdded(BlogPostCategory category)
			{
			}
		}

		class SummaryReader : XmlWrappingReader
		{
			int summaryChars;
			int readChars;
			bool skip;
			InitialDepthXmlReader moreDotsReader;
			XmlReader originalReader;

			public SummaryReader(XmlReader baseReader, int summaryChars, string moreDots)
				: base(baseReader)
			{
				this.summaryChars = summaryChars;
				moreDotsReader = new InitialDepthXmlReader(XmlReader.Create(new StringReader(moreDots)));
				moreDotsReader.MoveToContent();
			}

			public override bool Read()
			{
				if (skip)
				{
					if (BaseReader == moreDotsReader)
					{
						if (BaseReader.Read())
						{
							return true;
						}
						else
						{
							BaseReader = originalReader;
						}
					}
					else if (!moreDotsReader.EOF)
					{
						moreDotsReader.initialDepth = Depth;
						originalReader = BaseReader;
						BaseReader = moreDotsReader;
						return true;
					}

					int closeDepth = Depth - 1;
					bool read = BaseReader.Read();
					if (read)
					{
						while (Depth >= closeDepth)
						{
							if (!BaseReader.Read())
								return false;
						}
					}
					return read;
				}
				else
				{
					bool read = base.Read();
					if (read && NodeType == XmlNodeType.Text)
					{
						readChars += this.Value.Length;
						if (readChars > summaryChars)
							skip = true;
					}
					return read;
				}
			}
		}

		class InitialDepthXmlReader : XmlWrappingReader
		{
			internal int initialDepth;

			public InitialDepthXmlReader(XmlReader baseReader)
				: base(baseReader)
			{
			}

			public override int Depth
			{
				get
				{
					return base.Depth + initialDepth;
				}
			}
		}

		class ComboBoxItem
		{

			public ComboBoxItem()
			{

			}

			public ComboBoxItem(string text, string value, object tag)
			{
				Text = text;
				Value = value;
				Tag = tag;
			}

			public string Text { get; set; }
			public string Value { get; set; }
			public object Tag { get; set; }

			public override string ToString()
			{
				if (!string.IsNullOrEmpty(Text))
				{
					return Text;
				}
				return base.ToString();
			}

		}



	}
}
